#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <math.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include "libcli.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/wait.h>


#define HAVE_STRCASECMP 1

#define PCF8574_DTEST 1

#if (PCF8574_DTEST == 1)
#define PRT(...) printf(__VA_ARGS__)
#else 
#define PRT(...) 
#endif



#ifdef __GNUC__
# define UNUSED(d) d __attribute__ ((unused))
#else
# define UNUSED(d) d
#endif

#if !defined(HAVE_STRCASECMP) && defined(_MSC_VER)
# define strcasecmp _stricmp
#elif !defined(HAVE_STRCASECMP)
# error You do not have strcasecmp on your system.
#endif /* HAVE_STRNCASECMP */



#define CLITEST_PORT                8002
#define MODE_CONFIG_INT             10

static unsigned int regular_count = 0;
static unsigned int debug_regular = 0;

#define no_argument        0
#define required_argument  1
#define optional_argument  2


typedef unsigned char   uint8;
typedef unsigned short  uint16;
typedef unsigned int   uint32; 

typedef short           int16;
typedef long            int32;

#define PROC_FILE_8337  "/proc/procfs_example/8337"

#define PROC_FILE_8033  "/proc/procfs_8033/8033"

#define PROC_FILE_I2C  "/proc/procfs_i2c/i2c"


int hex2dec(char *hex)
{
    if (strncmp(hex, "0x", 2) == 0)
    {
        hex += 2;
    }

    int oct = 0, count = 0;

    while (1 && count < 8)
    {
        if (hex[count] >= '0' && hex[count] <= '9')
        {
            oct = (oct << 4) + (hex[count] - '0');
        }
        else if (hex[count] >= 'a' && hex[count] <= 'f')
        {
            oct = (oct << 4) + (hex[count] - 'a' + 10);
        }
        else if (hex[count] >= 'A' && hex[count] <= 'F')
        {
            oct = (oct << 4) + (hex[count] - 'A' + 10);
        }
        else
        {
            break;
        }
        
        count++;
    }

    return oct;
}

static void print_usage(const char *prog)
{
    printf("Usage: %s [-r:w:n:i:l:G:h:vFdcsp::t::D::]\n", prog);
    puts("  -r --read      read (e.g: -d cpld -i 1 -r 0x0c)\n"
         "  -w --write     write(e.g: -d cpld -i 1 -w 0x0c 0x01)\n"
         "  -n --name      point to io device name\n"
         "  -i --index     point to io device index\n"
         "  -p --probe     i2c probe\n"
         "  -l --length    set io array length\n"
         "  -c --cli       create cli daemon\n"
         "  -d --daemon    run as daemon\n"
         "  -v --version   show the software version\n"
         "  -s --slot      get card slot\n"
         "  -h --watchdog  enable/disable watchdog (e.g: -h enable|disable)\n"
         "  -t --cardtype  get cardtype from slot (e.g: -t 1)\n"
         "  -D --cardlabel dump card label from slot (e.g: -D 1)\n"
         "  -F --getfanpwm get fan pwm \n"
         "  -G --setfanpwm set fan pwm \n");
    exit(1);
}

int idle_process()
{
    static int count = 0;

    count++;

    return 0;
}

int gpio_to_mdio_read(int addr)
{
	    int fd,ret;
        int data = 0;
		int value;
		char str_buf[12]={0};

	

        fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        printf("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

    
		*(int *)str_buf = 2;         

		*(int *)&str_buf[4] = addr;
	
        ret = write(fd, str_buf, 12); 
	    if (ret)
		{
			printf("write\n"); 
	    }

		ret = read(fd, &data, 4);
	    if (ret)
		{
			printf("read\n"); 
	    }
		

		close(fd);  
		return data;
		
}

int gpio_to_8033_read(int addr)
{
	    int fd,ret;
        int data = 0;
		int value;
		char str_buf[12]={0};

	

        fd = open(PROC_FILE_8033, O_RDWR);              
        if (fd < 0) {  
		        printf("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

    
		*(int *)str_buf = 2;         

		*(int *)&str_buf[4] = addr;
	
        ret = write(fd, str_buf, 12); 
	    if (ret)
		{
			printf("write\n"); 
	    }

		ret = read(fd, &data, 4);
	    if (ret)
		{
			printf("read\n"); 
	    }
		

		close(fd);  
		return data;
		
}


int gpio_to_guang_read(void)
{
	    int fd,ret;
        int data = 0;
		int value;
		char str_buf[12]={0};

	

        fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        printf("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

    
		*(int *)str_buf = 4;         

		*(int *)&str_buf[4] = 1;
	
        ret = write(fd, str_buf, 12); 
	    if (ret)
		{
			printf("write\n"); 
	    }

		ret = read(fd, &data, 4);
	    if (ret)
		{
			printf("read\n"); 
	    }
		

		close(fd);  
		return data;
		
}


int gpio_to_sfp_read(int index,int addr)
{
	    int fd,ret;
        int data = 0;
		int value;
		char str_buf[12]={0};

	

        fd = open(PROC_FILE_I2C, O_RDWR);              
        if (fd < 0) {  
		        printf("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

    
		*(int *)str_buf = index;         

		*(int *)&str_buf[4] = addr;

		*(int *)&str_buf[8] = 1;
	
        ret = write(fd, str_buf, 12); 
	    if (ret)
		{
			printf("write\n"); 
	    }

		ret = read(fd, &data, 4);
	    if (ret)
		{
			printf("read\n"); 
	    }
		

		close(fd);  
		return data;
		
}



int gpio_to_boma_read(void)
{
	    int fd,ret;
        int data = 0;
		int value;
		char str_buf[12]={0};

	

        fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        printf("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

    
		*(int *)str_buf = 3;         

		*(int *)&str_buf[4] = 1;
	
        ret = write(fd, str_buf, 12); 
	    if (ret)
		{
			printf("write\n"); 
	    }

		ret = read(fd, &data, 4);
	    if (ret)
		{
			printf("read\n"); 
	    }
		

		close(fd);  
		return data;
		
}




int gpio_to_mdio_write(int addr,int value)
{
	    int fd,ret;
        unsigned char data = 0;

		char str_buf[12]={0};

	    fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        perror("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

			*(int *)str_buf = 1;         


			*(int *)&str_buf[4] = addr;

			*(int *)&str_buf[8] = value;

			
			
	        ret = write(fd, str_buf, 12); 
			if (ret)
			{
				printf("write\n"); 
			}

			ret = read(fd, &data, 4);
			if (ret)
			{
				printf("read\n"); 
			}
			
			
			close(fd);	
			return data;


}


int gpio_to_sfp_write(int index,int addr,int value)
{
	    int fd,ret;
        unsigned char data = 0;

		char str_buf[12]={0};

	    fd = open(PROC_FILE_I2C, O_RDWR);              
        if (fd < 0) {  
		        perror("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

            if(index == 0)
            	{
        			*(int *)str_buf = 1;         
            	}else {
					*(int *)str_buf = 3;		 

            	}

			*(int *)&str_buf[4] = addr;

			*(int *)&str_buf[8] = value;

			
			
	        ret = write(fd, str_buf, 12); 
			if (ret)
			{
				printf("write\n"); 
			}

			ret = read(fd, &data, 4);
			if (ret)
			{
				printf("read\n"); 
			}
			
			
			close(fd);	
			return data;


}


int gpio_to_guang_write(int addr,int value)
{
	    int fd,ret;
        unsigned char data = 0;

		char str_buf[12]={0};

	    fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        perror("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  


			*(int *)str_buf = 4;		 


			*(int *)&str_buf[4] = addr;

			*(int *)&str_buf[8] = value;

			
			
	        ret = write(fd, str_buf, 12); 
			if (ret)
			{
				printf("write\n"); 
			}

			ret = read(fd, &data, 4);
			if (ret)
			{
				printf("read\n"); 
			}
			
			
			close(fd);	
			return data;


}

int gpio_to_reset_write(int addr,int value)
{
	    int fd,ret;
        unsigned char data = 0;

		char str_buf[12]={0};

	    fd = open(PROC_FILE_8337, O_RDWR);              
        if (fd < 0) {  
		        perror("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  


			*(int *)str_buf = 6;		 


			*(int *)&str_buf[4] = addr;

			*(int *)&str_buf[8] = value;

			
			
	        ret = write(fd, str_buf, 12); 
			if (ret)
			{
				printf("write\n"); 
			}

			ret = read(fd, &data, 4);
			if (ret)
			{
				printf("read\n"); 
			}
			
			
			close(fd);	
			return data;


}




int gpio_to_8033_write(int addr,int value)
{
	    int fd,ret;
        unsigned char data = 0;

		char str_buf[12]={0};

	    fd = open(PROC_FILE_8033, O_RDWR);              
        if (fd < 0) {  
		        perror("Open device file err:");  
			        close(fd);  
				        return -1;  
		}  

			*(int *)str_buf = 1;         


			*(int *)&str_buf[4] = addr;

			*(int *)&str_buf[8] = value;

			
			
	        ret = write(fd, str_buf, 12); 
			if (ret)
			{
				printf("write\n"); 
			}

			ret = read(fd, &data, 4);
			if (ret)
			{
				printf("read\n"); 
			}
			
			
			close(fd);	
			return data;


}


int cmd_8337_read(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int tValue = 0;


	 
	cli_print(cli,"<reg> <value> 1");


	if(argc < 1 || strncmp(argv[0],"?",1) == 0)
	{
		cli_print(cli,"<reg>");
		return CLI_OK;
	}

	reg = hex2dec(argv[0]);
	
    tValue = gpio_to_mdio_read(reg);

	cli_print(cli,"reg %s, value = 0x%0x",argv[0],tValue);

   return CLI_OK;
}


int cmd_8033_read(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int tValue = 0;


	 
	cli_print(cli,"<reg> <value> 1");


	if(argc < 1 || strncmp(argv[0],"?",1) == 0)
	{
		cli_print(cli,"<reg>");
		return CLI_OK;
	}

	reg = hex2dec(argv[0]);
	
    tValue = gpio_to_8033_read(reg);

	cli_print(cli,"reg %s, value = 0x%0x",argv[0],tValue);

   return CLI_OK;
}


int cmd_boma_read(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int tValue = 0;

	
    tValue = gpio_to_boma_read();

	cli_print(cli,"boma, value = 0x%0x",tValue);

   return CLI_OK;
}

int cmd_sfp_read(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int tValue = 0;

	
	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<slot> <addr>");
		return CLI_OK;
	}

	
	if(argc == 2)
	{
		 reg = hex2dec(argv[0]);
		 value = hex2dec(argv[1]);
		
		if(reg == 1)
  		 tValue =  gpio_to_sfp_read(1,value);
		else if(reg == 2)
		 tValue =   gpio_to_sfp_read(2,value);


		cli_print(cli,"boma, value = 0x%0x",tValue);
	}

   return CLI_OK;
}


int cmd_guang_read(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int tValue = 0;

	
    tValue = gpio_to_guang_read();

	cli_print(cli,"boma, value = 0x%0x",tValue);

   return CLI_OK;
}



int cmd_8337_write(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;


	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<reg> <value>");
		return CLI_OK;
	}

	if(argc == 2)
	{

		reg = hex2dec(argv[0]);
		value = hex2dec(argv[1]);


	   gpio_to_mdio_write(reg,value);
	}

   return CLI_OK;
}

int cmd_8033_write(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;


	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<reg> <value>");
		return CLI_OK;
	}

	reg = hex2dec(argv[0]);
	value = hex2dec(argv[1]);

	if(argc == 2)
	{
	   gpio_to_8033_write(reg,value);
	}

   return CLI_OK;
}

int cmd_guang_write(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;


	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<reg> <value>");
		return CLI_OK;
	}

	reg = hex2dec(argv[0]);
	value = hex2dec(argv[1]);

	if(argc == 2)
	{
	   gpio_to_guang_write(reg,value);
	}

   return CLI_OK;
}

int cmd_reset_write(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;


	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<device 8337:8033> <value>");
		return CLI_OK;
	}
	if(argc == 2)
	{
        reg = strcmp(argv[0],"8337");
		reg = hex2dec(argv[0]);
		value = hex2dec(argv[1]);
		if(reg == 0)
    	    gpio_to_reset_write(1,value);
		else 
		    gpio_to_reset_write(2,value);
	}

   return CLI_OK;
}



int cmd_sfp_write(struct cli_def *cli, UNUSED(char *command), char *argv[], int argc)
{
    int32 ret = 0;
	uint8 cpld_idx = 0;
	int32 reg = 0;
    int32 value = 0;
	int32 index = 0;


	if(argc < 2 || strncmp(argv[0],"?",1) == 0|| strncmp(argv[1],"?",1) == 0 )
	{
		cli_print(cli,"<reg> <value>");
		return CLI_OK;
	}

	
	if(argc == 3)
	{

		index = hex2dec(argv[0]);
		reg = hex2dec(argv[1]);
		value = hex2dec(argv[2]);
    
	   gpio_to_sfp_write(index,reg,value);
	}

   return CLI_OK;
}



int check_auth(char *username, char *password)
{
    if (strcasecmp(username, "admin") != 0)
        return CLI_ERROR;
    if (strcasecmp(password, "admin") != 0)
        return CLI_ERROR;
    return CLI_OK;
}

int regular_callback(struct cli_def *cli)
{
    regular_count++;
    if (debug_regular)
    {
        cli_print(cli, "Regular callback - %u times so far", regular_count);
        cli_reprompt(cli);
    }
    return CLI_OK;
}

int check_enable(char *password)
{
    return !strcasecmp(password, "root");
}
void pc(UNUSED(struct cli_def *cli), char *string)
{
    printf("%s\n", string);
}


static void *
lai_cli_task(void *taskArg) 
{
    struct cli_command *c;
    struct cli_def *cli;
    int s, x;
    struct sockaddr_in addr;
    int on = 1;

    cli = cli_init();
    cli_set_banner(cli, "lai_cli test environment");
    cli_set_hostname(cli, "lai");
    cli_regular(cli, regular_callback);
    cli_regular_interval(cli, 1); // Defaults to 1 second
    cli_set_idle_timeout(cli, 180); // 60 second idle timeout
   
    c = cli_register_command(cli, NULL, "get", NULL, PRIVILEGE_UNPRIVILEGED,
        MODE_EXEC, "get infomation");
        
	cli_register_command(cli, c, "8337", cmd_8337_read, PRIVILEGE_UNPRIVILEGED,
        MODE_EXEC, "scan 8337 device");

	cli_register_command(cli, c, "8033", cmd_8033_read, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan 8033 device");

	cli_register_command(cli, c, "boma", cmd_boma_read, PRIVILEGE_UNPRIVILEGED,
					MODE_EXEC, "scan boma device");

	cli_register_command(cli, c, "guang", cmd_guang_read, PRIVILEGE_UNPRIVILEGED,
					MODE_EXEC, "scan guang device");		

	cli_register_command(cli, c, "sfp", cmd_sfp_read, PRIVILEGE_UNPRIVILEGED,
					MODE_EXEC, "scan sfp device");		


    c = cli_register_command(cli, NULL, "set", NULL, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "get infomation");
			
	cli_register_command(cli, c, "8337", cmd_8337_write, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan 8337 device");

	cli_register_command(cli, c, "8337", cmd_8033_write, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan 8033 device");

	cli_register_command(cli, c, "guang", cmd_guang_write, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan guang device");			

	cli_register_command(cli, c, "sfp", cmd_sfp_write, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan sfp device");		

	cli_register_command(cli, c, "reset", cmd_reset_write, PRIVILEGE_UNPRIVILEGED,
			MODE_EXEC, "scan sfp device");		

	cli_set_auth_callback(cli, check_auth);
    cli_set_enable_callback(cli, check_enable);
    // Test reading from a file
    {
        FILE *fh;

        if ((fh = fopen("clitest.txt", "r")))
        {
            // This sets a callback which just displays the cli_print() text to stdout
            cli_print_callback(cli, pc);
            cli_file(cli, fh, PRIVILEGE_UNPRIVILEGED, MODE_EXEC);
            cli_print_callback(cli, NULL);
            fclose(fh);
        }
    }

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return NULL;
    }
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    int port = CLITEST_PORT;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);
    while (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
        perror("bind");
        addr.sin_port = htons(++port);
    }

    if (listen(s, 50) < 0)
    {
        perror("listen");
        return NULL;
    }

    printf("lai cli is starting and listening on port %d\n", port);
    while ((x = accept(s, NULL, 0)))
    {
        cli_loop(cli, x);
        shutdown(x, 2);
        close(x);
    }

    cli_done(cli);
    return NULL;
}




void init_lai_cli()
{
    pthread_t thread_id;
    pthread_attr_t pthread_attr;
    struct sched_param sched;
    
    /* start trap socket read thread */
    sched.sched_priority = 45;
    pthread_attr_init(&pthread_attr);
    pthread_attr_setstacksize(&pthread_attr, 128*1024);
    pthread_attr_setschedpolicy (&pthread_attr, SCHED_RR);
    pthread_attr_setschedparam (&pthread_attr,&sched);
    pthread_create(&thread_id, &pthread_attr, lai_cli_task, NULL);
    pthread_attr_destroy(&pthread_attr);
}



static void parse_opts(int argc, char *argv[])
{


    int c, d, para_num = 0, index = 0, length = 1, i;
    char str[16] = {0};
    uint32 reg, value[256] = {0};
    int32 slot = 0, ret = 0;

    while (1)
    {
         	init_lai_cli();
            
            while (1)
            {
                idle_process();
                sleep(5);
            }
   }
}
    



int main(int argc,char **argv)
{


    parse_opts(argc, argv);
    
     return 0;
}

